package com.team2.imageComparison;
import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import static com.googlecode.javacv.cpp.opencv_highgui.*;

import com.googlecode.javacv.CanvasFrame;
import com.googlecode.javacv.JavaCV;
import com.googlecode.javacv.cpp.opencv_core.CvMat;
import com.googlecode.javacv.cpp.opencv_core.CvPoint2D32f;
import com.googlecode.javacv.cpp.opencv_core.CvSize;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
import com.googlecode.javacv.cpp.opencv_features2d;
import com.googlecode.javacv.cpp.opencv_features2d.DMatch;
import com.googlecode.javacv.cpp.opencv_features2d.DescriptorExtractor;
import com.googlecode.javacv.cpp.opencv_features2d.DrawMatchesFlags;
import com.googlecode.javacv.cpp.opencv_features2d.FeatureDetector;
import com.googlecode.javacv.cpp.opencv_features2d.FlannBasedMatcher;
import com.googlecode.javacv.cpp.opencv_features2d.KeyPoint;
import com.googlecode.javacv.cpp.opencv_imgproc.CvHistogram;
import com.googlecode.javacv.cpp.opencv_nonfree;
import com.googlecode.javacv.cpp.opencv_nonfree.SURF;
import static com.googlecode.javacv.cpp.opencv_features2d.*;
import static com.googlecode.javacv.cpp.opencv_calib3d.*;

import com.googlecode.javacv.cpp.opencv_core;

public class CyberImageMatcher {
	public static double getMatchedArea (String targetPath, String candidatePath){
		
		IplImage imgo = cvLoadImage(targetPath); 
		IplImage imgs = cvLoadImage(candidatePath);
		int height_obj, height_sce,height_out;
		height_obj = imgo.height();
		height_sce = imgs.height();
		if(height_obj>height_sce) height_out = height_obj;
		else height_out = height_sce;
		CvMat imageobj = imgo.asCvMat();
		CvMat imagescene = imgs.asCvMat();
		//CvMat out = imageobj.clone();
		SURF surf = new SURF(300, 3, 4, true, true); 
		FeatureDetector detector = surf.getFeatureDetector();
		//opencv_nonfree on = new openvc_nonfree();
		//SurfDescriptorExtractor d = new SurfDescriptorExtractor();
		DescriptorExtractor descriptor = surf.getDescriptorExtractor();
		KeyPoint obj_keypoints = new KeyPoint(); 
        KeyPoint scene_keypoints = new KeyPoint();
        CvMat obj_descriptors = new CvMat(null); 
        CvMat scene_descriptors = new CvMat(null); 
        detector.detect(imageobj, obj_keypoints, null); 
        detector.detect(imagescene, scene_keypoints, null); 
        descriptor.compute(imageobj, obj_keypoints, obj_descriptors); 
        descriptor.compute(imagescene, scene_keypoints, scene_descriptors);
        //System.out.println(obj_descriptors);
        FlannBasedMatcher matcher = new FlannBasedMatcher(); 
        DMatch matches = new DMatch();
        matcher.match(obj_descriptors,scene_descriptors,matches,null); 
        //System.out.println("capacity: "+matches.capacity());
        int i;
        double max_dist = 0; double min_dist = 100;
        for(i=0;i<matches.capacity();i++){
        	double dist = matches.position(i).distance();
            if( dist < min_dist ) min_dist = dist;
            if( dist > max_dist ) max_dist = dist;
        	//System.out.println("match "+i+" "+matches.position(i).distance());
        	
        }
       // int j = 0, rows = obj_descriptors.rows();
       // DMatch good_matches = new DMatch(rows);
        int j = 0, size = matches.capacity();
        DMatch good_matches = new DMatch(size);
        //double sum=0;
        for (i = 0; i < size; i++) {
            if (matches.position(i).distance() < 3*min_dist) {
                //no crash
            	//sum+=matches.position(i).distance();
                good_matches.position(j).distance(((DMatch)(matches.position(i))).distance());
                good_matches.position(j).imgIdx(((DMatch)(matches.position(i))).imgIdx());
                good_matches.position(j).queryIdx(((DMatch)(matches.position(i))).queryIdx());
                good_matches.position(j).trainIdx(((DMatch)(matches.position(i))).trainIdx());
                j++;
            }
        }
        good_matches.limit(j);
        IplImage outimg = cvCreateImage(new CvSize(imgo.width() + imgs.width(), height_out), imgo.depth(), 3);
        CvMat out =new CvMat();
        out = outimg.asCvMat();
      //  CvMat out = imageobj.clone();
        //CvMat out = new CvMat();
        
       // out=out.create(imageobj.rows(), imageobj.cols()+imagescene.cols());
        matches.position(0);
        good_matches.position(0);
        drawMatches(imageobj,obj_keypoints,imagescene,scene_keypoints,good_matches,out,cvScalarAll(-1),cvScalarAll(-1),null, 
        		DrawMatchesFlags.DEFAULT); 
        
        //double average = sum/j;
        /*int goodmatchsize = good_matches.capacity();
        double sum = 0;
        for(i=0;i<goodmatchsize;i++){
        	sum+=good_matches.position(i).distance();
        }
        double average_distance = sum/goodmatchsize;
        return average_distance;*/
        
        int n = matches.capacity();
        CvMat localpt1  = CvMat.create(1, n, CV_32F, 2);
        CvMat localpt2  = CvMat.create(1, n, CV_32F, 2);
        CvMat localmask = CvMat.create(1, n, CV_8U, 1);
        CvMat  H = CvMat.create(3, 3);
        double[] srcPtsD = new double[] {0, 0,  imageobj.cols(), 0,  imageobj.cols(), imageobj.rows(),  0, imageobj.rows()};
        double[] dstPtsD = new double[] {0, 0, 0, 0, 0, 0, 0, 0};
        

        for (i = 0; i < n; i++) {
        	CvPoint2D32f p1 = (obj_keypoints.position(matches.position(i).queryIdx())).pt();
            //CvPoint2D32f p1 = obj_keypoints.pt();
            localpt1.put(i*2, p1.x()); localpt1.put(i*2 + 1, p1.y());
           // logger.debug("object " + p1.x() + " / " + p1.y());

        }

        for (i = 0; i < n; i++) {
        	CvPoint2D32f p2 = (scene_keypoints.position(matches.position(i).trainIdx())).pt();
            //CvPoint2D32f p2 = scene_keypoints.pt();
            localpt2.put(i*2, p2.x()); localpt2.put(i*2+1, p2.y());
            //logger.debug("scene " + p2.x() + " / " + p2.y());
        }

        if (cvFindHomography(localpt1, localpt2, H, CV_RANSAC, 3.0, localmask) == 0){
            return -1;
        }

        double[] h = H.get();
        //System.out.println("H is: "+H);
        double[] srcCorners = {0, 0,  imageobj.cols(), 0,  imageobj.cols(),
        		imageobj.rows(),  0, imageobj.rows()};
        double[] dstCorners = new double[8];
        JavaCV jc = new JavaCV();
        jc.perspectiveTransform(srcCorners, dstCorners, H);
        
        double x1,y1,x2,y2,x3,y3,x4,y4;
        x1 = dstCorners[0]; y1 = dstCorners[1];
        x2 = dstCorners[2]; y2 = dstCorners[3];
        x3 = dstCorners[4]; y3 = dstCorners[5];
        x4 = dstCorners[6]; y4 = dstCorners[7];
        double area = ((x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y4 - y3*x4) + (x4*y1 - y4*x1))/2;
        //if(area<0) area = area*(-1);
        //System.out.println("area is: "+ area);
        //cvDrawLine(out, new CvPoint(srcCorner.position(0).x(),pts.position(0).y()), new CvPoint(pts.position(1).x(),pts.position(1).y()), CvScalar.GREEN, 3, CV_AA, 0);
        //cvDrawLine(out, new CvPoint(pts.position(1).x(),pts.position(1).y()), new CvPoint(pts.position(2).x(),pts.position(2).y()), CvScalar.GREEN, 3, CV_AA, 0);
        //cvDrawLine(out, new CvPoint(pts.position(2).x(),pts.position(2).y()), new CvPoint(pts.position(3).x(),pts.position(3).y()), CvScalar.GREEN, 3, CV_AA, 0);
        //cvDrawLine(out, new CvPoint(pts.position(3).x(),pts.position(3).y()), new CvPoint(pts.position(0).x(),pts.position(0).y()), CvScalar.GREEN, 3, CV_AA, 0);
        //CanvasFrame canvas = new CanvasFrame("My Image");

        // request closing of the application when the image window is closed
        //canvas.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);

        // show image on window*/
        //cvSaveImage("test.jpg",out); 
        //System.out.println("done");
        //cvShowImage("test",out);
        return area;
	}
}
